有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java是Lucene 4中允许对数值字段进行范围查询的最简单方法

我正在重温最初为Lucene 3.0编写的代码(然后我对其进行了更新,使其适用于4.0,但尚未充分利用4.0的所有改进)

对于我希望能够进行范围查询的数字字段,我将字段添加到文档中,如下所示:

BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT);
NumericUtils.intToPrefixCoded(value, 0, bytes);
doc.add(new Field(fieldname, bytes.utf8ToString(),
    new FieldType(StringField.TYPE_NOT_STORED)));

然后我必须有一个自定义的查询解析器来覆盖方法newTermQuery()和new RangeQuery()

public class ReleaseQueryParser extends MultiFieldQueryParser
{

    public ReleaseQueryParser(String[] strings, Analyzer a)
    {
        super(LuceneVersion.LUCENE_VERSION, strings, a);
    }

    protected Query newTermQuery(Term term)
    {
        if (
                (term.field().equals(ReleaseIndexField.NUM_TRACKS.getName())) ||
                        (term.field().equals(ReleaseIndexField.NUM_TRACKS_MEDIUM.getName())) ||
                        (term.field().equals(ReleaseIndexField.NUM_MEDIUMS.getName()))
                )
        {
            try
            {

                int number = Integer.parseInt(term.text());
                BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT);
                NumericUtils.intToPrefixCoded(number, 0, bytes);
                TermQuery tq = new TermQuery(new Term(term.field(), bytes.utf8ToString()));
                return tq;
            }
            catch (NumberFormatException nfe)
            {
                //If not provided numeric argument just leave as is, won't give matches
                return super.newTermQuery(term);
            }
        }
        else
        {
            return super.newTermQuery(term);

        }
    }

    @Override
    public Query newRangeQuery(String field,
                               String part1,
                               String part2,
                               boolean startInclusive,
                               boolean endInclusive)
    {
        if (
                (field.equals(ReleaseIndexField.NUM_TRACKS.getName())) ||
                        (field.equals(ReleaseIndexField.NUM_TRACKS_MEDIUM.getName())) ||
                        (field.equals(ReleaseIndexField.NUM_MEDIUMS.getName()))
                )
        {
            BytesRef bytes1 = new BytesRef(NumericUtils.BUF_SIZE_INT);
            BytesRef bytes2 = new BytesRef(NumericUtils.BUF_SIZE_INT);
            NumericUtils.intToPrefixCoded(Integer.parseInt(part1), 0, bytes1);
            NumericUtils.intToPrefixCoded(Integer.parseInt(part2), 0, bytes2);
            part1 = bytes1.utf8ToString();
            part2 = bytes2.utf8ToString();
        }
        TermRangeQuery query = (TermRangeQuery)
                super.newRangeQuery(field, part1, part2, startInclusive, endInclusive);
        return query;

    }
}

我一直认为这段代码很笨重,想知道它现在是否可以简化一些

更新

试图按如下方式使用IntField

医生。添加(新的IntField(field.getName(),value,新的FieldType(StringField.TYPE_NOT_STORED))

编译好了,但我的索引构建测试方法

Fields fields = MultiFields.getFields(ir);
Terms terms = fields.terms(field.getName());
TermsEnum termsEnum = terms.iterator(null);
termsEnum.next();
assertEquals(value, NumericUtils.prefixCodedToInt(termsEnum.term()));

因条款上的NullPointerException而失败。迭代器()行

改为

doc.add(new IntField(field.getName(), value, new FieldType(IntField.TYPE_NOT_STORED)));

这很管用,但令我惊讶的是

NumericUtils.prefixCodedToInt(termsEnum.term())

仍然有效,我猜IntField只是我最初拥有的ByteRef代码的包装器

然后重写QueryParser,如下所示

public class ReleaseQueryParser extends MultiFieldQueryParser
{

    public ReleaseQueryParser(String[] strings, Analyzer a)
    {
        super(LuceneVersion.LUCENE_VERSION, strings, a);
    }

    protected Query newTermQuery(Term term)
    {
        if (
                (term.field().equals(ReleaseIndexField.NUM_TRACKS.getName())) ||
                        (term.field().equals(ReleaseIndexField.NUM_TRACKS_MEDIUM.getName())) ||
                        (term.field().equals(ReleaseIndexField.NUM_MEDIUMS.getName()))
                )
        {
            return NumericRangeQuery.newIntRange(term.field(), Integer.parseInt(term.text()), Integer.parseInt(term.text()), true, true);
        }
        else
        {
            return super.newTermQuery(term);

        }
    }

    @Override
    public Query newRangeQuery(String field,
                               String part1,
                               String part2,
                               boolean startInclusive,
                               boolean endInclusive)
    {
        if (
                (field.equals(ReleaseIndexField.NUM_TRACKS.getName())) ||
                        (field.equals(ReleaseIndexField.NUM_TRACKS_MEDIUM.getName())) ||
                        (field.equals(ReleaseIndexField.NUM_MEDIUMS.getName()))
                )
        {
            return NumericRangeQuery.newIntRange(field, Integer.parseInt(part1), Integer.parseInt(part2),startInclusive, endInclusive);
        }
        else
        {
            return super.newRangeQuery(field, part1, part2, startInclusive, endInclusive);
        }
    }
}

这很管用,我真的不想在newTermQuery(术语)中使用范围查询,但我找不到更简单的方法


共 (1) 个答案

  1. # 1 楼答案

    使用lucene提供的IntFieldLongField类。然后,您可以使用指定类型的标准NumericRangeQuery查询索引